package com.starry.module.system.core.oauth2.authorization.provider;


import com.starry.core.common.constants.CommonConstant;
import com.starry.core.common.execption.ServiceException;
import com.starry.core.redis.service.RedisService;
import com.starry.module.system.core.checkcode.service.CheckCodeService;
import com.starry.module.system.core.oauth2.authorization.constant.SecurityConstants;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * 短信验证码校验实现
 *
 * @author 小柯
 */
@Slf4j
@Component
public class CaptchaLoginAuthenticationProvider extends CaptchaAuthenticationProvider {

    private final RedisService redisService;

    /**
     * 利用构造方法在通过{@link Component}注解初始化时
     * 注入UserDetailsService和passwordEncoder，然后
     * 设置调用父类关于这两个属性的set方法设置进去
     *
     * @param userDetailsService 用户服务，给框架提供用户信息
     * @param passwordEncoder    密码解析器，用于加密和校验密码
     */
    public CaptchaLoginAuthenticationProvider(UserDetailsService userDetailsService, PasswordEncoder passwordEncoder, RedisService redisService, CheckCodeService checkCodeService) {
        super(userDetailsService, passwordEncoder, checkCodeService);
        this.redisService = redisService;
    }

    @Override
    protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {

        if (authentication.getCredentials() == null) {
            throw new BadCredentialsException("短信验证码不能为空");
        }

        String grantType = getGrantType();
        // 内部认证
        if (CommonConstant.INTERNAL_CLIENT_GRANT_TYPE.equals(grantType)) {
            return;
        }

        // 第三方认证
        if (SecurityConstants.GRANT_TYPE_THIRD.equals(grantType)) {
            return;
        }

        // 短信登录
        if (SecurityConstants.GRANT_TYPE_SMS_CODE.equals(grantType)) {
            return;
        }

        // 其它调用父类默认实现的密码方式登录
        super.additionalAuthenticationChecks(userDetails, authentication);
    }

    private static String getGrantType() {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (requestAttributes == null) {
            throw new ServiceException("Failed to get the current request.");
        }
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
        // 获取grant_type
        return request.getParameter(OAuth2ParameterNames.GRANT_TYPE);
    }
}
